import dailog as dlog
import importlib
import uuid
import time
import pygame
import threading
import requests
import os
import sys
import socket
import traceback
import json
import rich.console


# Init-1
console = rich.console.Console()
version = "1.1.1"
verid =111
#console.clear()
pygame.init()

# Init-2
console.log("[Init-2] Reading config.json")
with open("config.json",encoding = "utf-8") as f:
    config = json.load(f)
console.log("Data in config.json: ",config)

# Init-3
console.log("[Init-3] Initing main window . . .")
screen = pygame.display.set_mode(config["window.size"])
pygame.display.set_caption(config["title"])

# Init-4
console.log("[Init-4] Initing values . . .")
page_list = []
pages = {}
scr = "<login>"
bg = [255,255,255]
temp1 = ""
plugin_data = {}
eventcon = []
icons = []
plugins = {}
user = {"uuid":"","name":"<default>"}
threads = []



# Init-5-1
console.log("[Init-5-1] Initing XAPI")
class xapi():

    dialog = dlog
    def setglobalvalue(key,value):
        if type(value) == type("114514"):
            v = f"\"{value}\""
        else:
            v = value
        exec(f"""global {key}
{key} = {v}""")
    def getglobalvalue(name):
        exec(f"""global {name}
global temp1
temp1 = {name}""")
        global temp1
        return temp1
    def get_data(key,default):
        global user
        uuid =user["uuid"]
        data = json.loads(requests.get(f"http://124.222.63.135:8080/getdata/{uuid}/{key}").text)
        if data["code"] == 404:
            try:
                data = json.loads(requests.get(f"http://124.222.63.135:8080/savedata/{uuid}/{key}/{json.dumps(default)}").text)
                return default
            except:
                return None
        return data["data"]
    
    def set_data(key,value):
        global user
        uuid = user["uuid"]
        data = json.loads(requests.get(f"http://124.222.63.135:8080/savedata/{uuid}/{key}/{json.dumps(value)}").text)
        return data

    def get_publicdata(key,default = '""'):
        data = json.loads(requests.get(f"http://124.222.63.135:8080/getpublicdata/{key}").text)
        if data["code"] == 404:
            try:
                data = json.loads(requests.get(f"http://124.222.63.135:8080/setpublicdata/{key}/{json.dumps(default)}").text)
                return default
            except:
                return None
        return data["data"]
    
    def set_publicdata(key,value):
        global user
        uuid = user["uuid"]
        data = json.loads(requests.get(f"http://124.222.63.135:8080/setpublicdata/{key}/{json.dumps(value)}").text)
        return data


    def setvalue(key,value):
        global plugin_data
        plugin_data[key] = value

    def getvalue(key):
        global plugin_data
        return plugin_data[key]
    def autocenter(surface):
        global config
        return (config["window.size"][0] - surface.get_size()[0]) / 2
    def center(surface,x,size=0):
        return (x - surface.get_size()[size]) / 2
    
    def center_verti(surface):
        global config
        return (config["window.size"][1] - surface.get_size()[1]) / 2
    def multline(*lines,font,color = (0,0,0), bg = (255,255,255),center = True,linec = 5):
        global config,console
        max_x = 0
        y = 0
        surface = pygame.surface.Surface(config["window.size"])
        surface.fill(bg)
        for line in lines:
            obj = font.render(line,True,color,bg)
            surface.blit(obj,(0,y))
            y += obj.get_size()[1] + 5
            if max_x < obj.get_size()[0]:
                max_x = obj.get_size()[0]
                
        sur1 = pygame.surface.Surface((max_x,y))
        sur1.fill(bg)
        y = 0
        if center:
            for li in lines:
                obj1 = font.render(li,True,color,bg)
                sur1.blit(obj1,(xapi.center(obj1,max_x),y))
                #console.log(xapi.center(obj1,max_x))
                y += obj.get_size()[1] + 5
        else:
            sur1.blit(surface,(0,0))
        #console.log(sur1,max_x)
        return sur1
    def execute(code):
        exec(code)
    def addpage(name,function,icon,thread = True,size = config["window.size"],settings = {}):
        global pages,config,page_list,consile
        sur1 = pygame.surface.Surface(size)
        page_list += [name]
        console.log(icon,sur1)
        ico = pygame.image.load(icon)
        pages[name] = {"screen":sur1,"icon":ico,"class":function,"t":thread,"config":settings}
        return pages[name]["screen"]
    def waitforfunc(function,return_value = True):
        while function() != return_value:
            pass
    def getpath(path):
        return path.replace("\\","/").replace("./","./plugins/data/")
    def newThread(name,function):
        global threads
        thread = threading.Thread(None,function)
        thread.setDaemon(True)
        thread.setName(name)
        thread.start()
        threads += [thread]
        return thread

    class main():
        def execute(code):
            return xapi.execute(code)
        def setvalue(name,value):
            return xapi.setglobalvalue(name,value)
        def getvalue(name):
            return xapi.getglobalvalue(name)
    class user():
        def get():
            global user
            return user
        def getdata(key,default = ""):
            return xapi.get_data(key,default)
        def setdata(key,value):
            return xapi.set_data(key,value)
    class public():
        def get(key,default = ""):
            return xapi.get_publicdata(key,default)
        def set(key,value):
            return xapi.set_publicdata(key,value)
    class page():
        def add(name,function,icon,thread = True,size = config["window.size"],settings = {}):
            return xapi.addpage(name,function,icon,thread,size,settings)
        def icon(page,surface = None,color = config["colors"][2]):
            global icons
            icons += [{
                "name":page,
                "surface":surface,
                "color":color
            }]
        def event(event,function):
            global eventcon
            eventcon += [event,function]

console.log("Successful in initing 1 class!")

# Init-6
console.log("[Init-6] Loading plugins list (1) . . .")
try:
    os.mkdir("./plugins/data")
except:
    pass
plist = os.listdir("./plugins")
plist.pop(plist.index("data"))
console.log(f"There are {plist.__len__()} plugin(s) installed.",plist)

# Init-7-1
console.log("[Init-7-2] Loading plugins (2) . . . ")
p_success = []
for p in plist:
    try:
        plugins[p] = {}
        plugins[p]["module"] = importlib.import_module(f"plugins.{p[0:-3]}")
        plugins[p]["main"] = plugins[p]["module"].plugin(api = xapi,log = console.log)

    except Exception as e:
        console.log(f"[red]Error to load plugin {p}!")
        console.print_exception()
    else:
        console.log(f"Plugin {p} loaded.")
        p_success += [p]
console.log(f"Successful in loading {p_success} plugin(s).")
plist = p_success

# Init-7-2
console.log("[Init-7-2] Enableing plugins . . .")
for p in plist:
    try:
        xapi.newThread(f"Enable::{p}",lambda: plugins[p]["main"].onEnable(plugins[p]["main"]))
    except:
        console.print_exception()

# Init-8
console.log("[Init-8] Initing Threads . . .")
def thread_clear_thread():
    global threads
    len = 0
    while True:
        cled = 0
        len = 0
        for t in threads:
            if not(t.is_alive()):
                console.log(f"[ClearThread] Thread {t.getName()} was stopped, cleaning . . .")
                try:
                    threads.pop(len)
                except:
                    console.print_exception()
                cled += 1
                console.log("done.")
            len += 1
        if cled:
            console.log(f"[ClearThread] Cleaned {cled} thread(s).")
        time.sleep(1)
clear_thread = xapi.newThread("Clear-Thread",thread_clear_thread)

# Main
run = True
_scr = "114514"
zoom = False
while run:
    e = 0
    for event in pygame.event.get():
        e += 1
        for p in plist:
            plugins[p]["main"].onEvent(event)
        for ev in eventcon:
            if event.type == ev[0]:
                ev[1](event)
    try:
        #console.log(_scr,scr)
        if _scr != scr:     # 监控页面切换
            try:
                pages[_scr]["class"].pause(pages[_scr]["class"])
            except:
                pass
            pages[_scr]["class"].paused = True
            _scr = scr
            console.log("Setting page to",scr)
            pages[_scr]["class"].paused = False
            self = pages[scr]["class"](log = console.log, screen = pages[scr]["screen"], api = xapi)
            if pages[scr]["t"]:
                xapi.newThread(f"Screen::{scr}",lambda: pages[scr]["class"].onStart(self))
            else:
                pages[scr]["class"].onStart(self)
            
            
                    
        if not(pages[scr]["t"]):
            pages[scr]["class"].inPage()
            # console.log(2)
        
        #if zoom:
        #    sur = pygame.transform.scale(pages[scr]["screen"],config["window.size"])
        #    
        #    screen.blit(sur,(0,0))
        #else:
        sur = pages[scr]["screen"]
        #console.log(pygame.transform.scale(pages[scr]["screen"],config["window.size"]))
        screen.blit(sur,(0,0))
        #console.log(scr)
    except:
        console.print_exception()
        scr = "<default>"
    
    pygame.display.update()
    screen.fill(bg)
    pygame.time.delay(50)


console.log("Closing Pages . . .")
try:
    pages[scr]["class"].pause = True
    page_d = xapi.newThread("disablepage",pages[scr]["class"].pause(pages[scr]["class"]))
except:console.print_exception()

console.log("Disableing Plugins . . ")
for p in plist:
    try:
        plugins[p]["main"].onDisable(plugins[p]["main"])
    except:
        console.print_exception()

try:page_d.join()
except:pass

console.log("Done.")

sys.exit()
